package com.itheima.aop;

import com.itheima.mapper.OperateLogMapper;
import com.itheima.pojo.OperateLog;
import com.itheima.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.Arrays;

@Slf4j//打日志工具，默认为log
@Aspect//定义该类为切面类
@Component//注入容器
public class LogRecordAspect {

    @Autowired
    private HttpServletRequest request;

    @Autowired
    OperateLogMapper operateLogMapper;

    //使用自定义注解的方式引入AOP
    @Around("@annotation(com.itheima.anno.MyLog)")
    public Object recordLog(ProceedingJoinPoint pjp) throws Throwable {
        //1.操作人ID->当前登陆人ID
        //1.1获取请求头中的jwt令牌
        String jwt = request.getHeader("token");
        //1.2解析令牌
        Claims claims = JwtUtils.parseJWT(jwt);
        //1.3获取登录人ID
        Integer id = (Integer) claims.get("id");
        log.info("获取登陆人的ID：{}", id);

        //获取操作开始的时间
        LocalDateTime operateTime = LocalDateTime.now();
        log.info("获取操作开始的时间：{}", operateTime);

        //获取操作的类名
        String className = pjp.getTarget().getClass().getName();
        log.info("获取操作的类名：{}", className);

        //获取操作的方法名
        String methodName = pjp.getSignature().getName();
        log.info("获取操作的方法名：{}", className);

        //获取操作的方法参数
        Object[] args = pjp.getArgs();
        String argsStr = Arrays.toString(args);
        log.info("获取操作的方法参数：{}", argsStr);

        //获取到调用原始目标方法运行开始的时间
        long start = System.currentTimeMillis();
        log.info("操作开始的时间为：{}", start);

        //调用原始目标方法
        Object result = null;
        try {
            result = pjp.proceed();

        } finally {//执行目标方法可能会出错，但是错误日志一定要记录在数据库中
            log.info("调用原始目标方法,返回值为：{}", result);

            //获取到调用原始目标方法运行结束的时间
            long end = System.currentTimeMillis();
            log.info("操作结束的时间为：{}", end);

            //操作耗时
            long costTime = end - start;
            log.info("操作耗时为：{}", costTime);

            OperateLog operateLog = new OperateLog(
                    null, id, operateTime, className, methodName, argsStr, String.valueOf(result), costTime);
            operateLogMapper.insert(operateLog);
        }
        return result;
    }
}
